package org.moon.framework.autoconfigure.oss.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import org.moon.framework.autoconfigure.MoonConstants;
import org.moon.framework.autoconfigure.exception.domain.MoonException;
import org.moon.framework.autoconfigure.oss.OssService;
import org.moon.framework.autoconfigure.oss.OssTemplate;
import org.moon.framework.autoconfigure.oss.props.OssProperties;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.List;

/**
 * 基于 S3 协议的文件客户端，实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务
 *
 * S3 协议的客户端，采用亚马逊提供的 software.amazon.awssdk.s3 库
 *
 * @author 村口的大爷
 */
@Slf4j
public class S3OssService implements OssService {

    public static final String ENDPOINT_ALIYUN = "aliyuncs.com";

    private OssProperties ossProperties;
    private MinioClient client;

    public S3OssService(OssProperties ossProperties) {
        this.ossProperties = ossProperties;
        // 补全 domain
        if (StrUtil.isEmpty(ossProperties.getDomain())) {
            ossProperties.setDomain(buildDomain());
        }
        // 初始化客户端
        client = MinioClient.builder()
                .endpoint(buildEndpointURL()) // Endpoint URL
                .region(buildRegion()) // Region
                .credentials(ossProperties.getUserName(), ossProperties.getPassword()) // 认证密钥
                .build();
    }

    /**
     * 基于 endpoint 构建调用云服务的 URL 地址
     * @return URI 地址
     */
    private String buildEndpointURL() {
        // 如果已经是 http 或者 https，则不进行拼接.主要适配 MinIO
        if (HttpUtil.isHttp(ossProperties.getEndpoint()) || HttpUtil.isHttps(ossProperties.getEndpoint())) {
            return ossProperties.getEndpoint();
        }
        return StrUtil.format("https://{}", ossProperties.getEndpoint());
    }

    /**
     * 基于 bucket + endpoint 构建访问的 Domain 地址
     *
     * @return Domain 地址
     */
    private String buildDomain() {
        // 如果已经是 http 或者 https，则不进行拼接.主要适配 MinIO
        if (HttpUtil.isHttp(ossProperties.getEndpoint()) || HttpUtil.isHttps(ossProperties.getEndpoint())) {
            return StrUtil.format("{}/{}", ossProperties.getEndpoint(), ossProperties.getBasePath());
        }
        // 阿里云、腾讯云、华为云都适合。七牛云比较特殊，必须有自定义域名
        return StrUtil.format("https://{}.{}", ossProperties.getBasePath(), ossProperties.getEndpoint());
    }

    /**
     * 基于 bucket 构建 region 地区
     * @return region 地区
     */
    private String buildRegion() {
        // 阿里云必须有 region，否则会报错
        if (ossProperties.getEndpoint().contains(ENDPOINT_ALIYUN)) {
            return StrUtil.subBefore(ossProperties.getEndpoint(), '.', false)
                    .replaceAll("-internal", ""); // 去除内网 Endpoint 的后缀
        }
        return null;
    }

    @Override
    public String upload(byte[] content, String originalName) {
        // 执行上传
        try {
            String path = getFilePath(ossProperties.getBasePath(),originalName);
            client.putObject(PutObjectArgs.builder()
                    .bucket(ossProperties.getBasePath()) // bucket 必须传递
                    .object(path) // 相对路径作为 key
                    .stream(new ByteArrayInputStream(content), content.length, -1) // 文件内容
                    .build());
            // 拼接返回路径
            String link = ossProperties.getDomain() + File.separator + path;
            insert(ossProperties.getId(),originalName,link, OssTemplate.FileStorageEnum.S3);
            return link;
        }catch (Exception e){
            log.error(e.getMessage(),e);
            throw new MoonException(MoonConstants.OSS_UPLOAD_ERROR);
        }
    }

    @Override
    public void delete(String link){
        try {
            String path = StrUtil.replace(link, ossProperties.getDomain(), StrUtil.EMPTY);
            client.removeObject(RemoveObjectArgs.builder()
                    .bucket(ossProperties.getBasePath()) // bucket 必须传递
                    .object(path) // 相对路径作为 key
                    .build());
            delete(ossProperties.getId(),link);
        }catch (Exception e){
            log.error(e.getMessage(),e);
            throw new MoonException(MoonConstants.OSS_UPLOAD_ERROR);
        }
    }

    @Override
    public void batchDelete(List<String> links) {
        for(String link:links){
            delete(link);
        }
    }

    @Override
    public byte[] getContent(String link){
        try {
            String path = StrUtil.replace(link, ossProperties.getDomain(), StrUtil.EMPTY);
            GetObjectResponse response = client.getObject(GetObjectArgs.builder()
                    .bucket(ossProperties.getBasePath()) // bucket 必须传递
                    .object(path) // 相对路径作为 key
                    .build());
            return IoUtil.readBytes(response);
        }catch (Exception e){
            log.error(e.getMessage(),e);
            throw new MoonException(MoonConstants.OSS_UPLOAD_ERROR);
        }
    }
}